﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace The_LarX
{
    public class Wind : VegetationModifier
    {
        /// <summary>
        /// The Strenght of the Wind.
        /// </summary>
        public float Strenght { get; set; }
        /// <summary>
        /// If the PerturbTime is greater than Zero, 
        /// there will be perturbance on the Wind. 
        /// This variable handles the variance of 
        /// the Strenght of the Wind during the Perturbance.
        /// </summary>
        public float PerturbVariance { get; set; }
        /// <summary>
        /// The Time the Wind will take to Change 
        /// it’s Current PerturbVariance.
        /// </summary>
        public float PerturbTime { get; set; }
        /// <summary>
        /// Just how much time will the Tree 
        /// take to go to the Wind's desired rotation. 
        /// (Greater = Slower)
        /// </summary>
        public int AnimationSpeed { get; set; }

        /// <summary>
        /// The Max Distance for the Wind to be applied. If ZERO,
        /// the MaxDistance will be Infinite.
        /// </summary>
        public float MaxDistance { get; set; }

        /// <summary>
        /// After this Distance the Strenght will get lower,
        /// until it reach the MaxDistance. Isn’t applied
        /// if it’s value is ZERO, and if MaxDistance is ZERO.
        /// </summary>
        public float LoseStrenghtDistance { get; set; }

        /// <summary>
        /// The Direction of the Wind. 
        /// It’s the same as the 
        /// EditorRepresentation.Actor.RadiansRotation, 
        /// so you can set the Direction on the Editor 
        /// by just changing the Object’s Rotation. 
        /// </summary>
        public Vector3 Direction
        {
            get
            {
                return Representation.Actor.RadiansRotation;
            }
            set
            {
                Representation.Actor.RadiansRotation = value;
            }
        }

        public EditorRepresentation Representation;

        private int PerturbTimer;
        private float PerturbValue;

        public Wind(Renderer Renderer, GameScreen gs)
            : base(gs)
        {
            Representation = new EditorRepresentation("Engine\\Models\\arrow", Renderer);
            Representation.Actor.DegreesRotation = new Vector3(0, 0, 0);
            Representation.Actor.Parent = this;

            Strenght = 1;
            PerturbVariance = 0.3f;
            PerturbTime = 100;
            AnimationSpeed = 20;

            if (Engine.Editor)
            {
                Representation.Actor.SubActors[1].RemappedEffect = true;
                Texture2D tex = Engine.RenderManager.TransformTextInTexture("Wind",
                    new Vector2(10), new Vector2(256), "Kootenay", 0, Color.White,
                    Color.Black, 3);
                Representation.Actor.SubActors[1].DoubleSided = true;
                Representation.Actor.SubActors[1].Material.DiffuseMapTexture = tex;
                Representation.Actor.SubActors[1].TransparencyMode = SynapseGaming.LightingSystem.Core.TransparencyMode.None;
                Representation.Actor.SubActors[1].Material.EmissiveColor = Color.White.ToVector4();
            }
        }
        public Wind()
            : base()
        {
            Representation = new EditorRepresentation("Engine\\Models\\arrow");
            Representation.Actor.DegreesRotation = new Vector3(0, 0, 0);
            Representation.Actor.Parent = this;

            if (Engine.Editor)
            {
                Representation.Actor.SubActors[1].RemappedEffect = true;
                Texture2D tex = Engine.RenderManager.TransformTextInTexture("Wind",
                    new Vector2(10), new Vector2(256), "Kootenay", 0, Color.White,
                    Color.Black, 3);
                Representation.Actor.SubActors[1].DoubleSided = true;
                Representation.Actor.SubActors[1].Material.DiffuseMapTexture = tex;
                Representation.Actor.SubActors[1].TransparencyMode = SynapseGaming.LightingSystem.Core.TransparencyMode.None;
                Representation.Actor.SubActors[1].Material.EmissiveColor = Color.White.ToVector4();
            }
        }

        bool Add = false;
        public virtual void ResetRandomPerturb()
        {
            PerturbValue = RandomUtil.Next(0, PerturbVariance, 100);
            Add = RandomUtil.OneToOneHundredProbabilty(50);
            
            PerturbValues.Clear();
            AddValues.Clear();
            for (int i = 0; i < EngineSystem.Trees.Count; i++)
            {
                PerturbValues.Add(RandomUtil.Next(0, PerturbVariance, 100));
                AddValues.Add(RandomUtil.OneToOneHundredProbabilty(50));
            }
        }
        protected List<float> PerturbValues = new List<float>();
        protected List<bool> AddValues = new List<bool>();

        protected Vector3 WindDirection;

        private bool Selected;
        public override void PressedWhenSelected()
        {
            Selected = !Selected;
        }

        public override void Update()
        {
            base.Update();

            if (this.AddValues.Count != EngineSystem.Trees.Count)
            {
                PerturbTimer = 0;
                ResetRandomPerturb();
            }

            if (Engine.Editor)
            {               
                Representation.Update();

                float av = Vector3Util.Average(Representation.Actor.Scale);
                if (av > 1 || av < 1)
                {
                    float dif = av - 1;
                    if (Selected)
                    {
                        if (MaxDistance + (dif * 10) > 0)
                        {
                            MaxDistance += dif * 10;
                        }
                    }
                    else
                    {
                        if (LoseStrenghtDistance + (dif * 10) > 0)
                        {
                            LoseStrenghtDistance += dif * 10;
                        }
                    }
                }
                Representation.Actor.Scale = new Vector3(1);
            }

            WindDirection = Vector3.Transform(Vector3.Forward,
                Representation.Actor.RotationMatrix);
            WindDirection.Y = -WindDirection.X;
            WindDirection.X = 0;
            WindDirection /= 10;

            if (PerturbTimer < PerturbTime)
            {
                PerturbTimer += Engine.GameTime.ElapsedGameTime.Milliseconds;
            }
            else
            {
                PerturbTimer = 0;
                ResetRandomPerturb();
            }

            float DifferenceBetween = MaxDistance - LoseStrenghtDistance;

            for (int i = 0; i < EngineSystem.Trees.Count; i++)
            {
                if (EngineSystem.Trees[i] is Tree_Animated)
                {
                    Tree_Animated tree = EngineSystem.Trees[i] as Tree_Animated;

                    float distance = Vector3.Distance(tree.TreeActor.Position,
                        this.Representation.Position);
                    if (MaxDistance == 0 || distance < MaxDistance)
                    {
                        Vector3 useWindDirection = WindDirection;
                        if (AddValues[i])
                        {
                            useWindDirection *= Strenght + PerturbValues[i];
                        }
                        else
                        {
                            useWindDirection *= Strenght - PerturbValues[i];
                        }

                        Vector3 newWindDirection = Vector3.Transform(useWindDirection, tree.TreeActor.RotationMatrix);


                        if (LoseStrenghtDistance != 0 && distance > LoseStrenghtDistance)
                        {
                            float thisDif = MaxDistance - distance;
                            float div = (DifferenceBetween - thisDif);
                            div = MathHelper.Clamp(div, 1, DifferenceBetween);
                            newWindDirection /= div;
                        }
                        for (int k = tree.TreeActor.AnimationController.SkinnedBoneTransforms.Length - 1; k > 0; k--)
                        {
                            tree.TreeActor.AnimationController.SkinnedBoneCustomRotations[k] =
                                AnimationHelper.AnimateStatic(
                                tree.TreeActor.AnimationController.SkinnedBoneCustomRotations[k].Value,
                                newWindDirection, AnimationSpeed);
                        }
                    }
                    else
                    {
                        for (int k = tree.TreeActor.AnimationController.SkinnedBoneTransforms.Length - 1; k > 0; k--)
                        {
                            if (distance < MaxDistance * 2)
                            {
                                tree.TreeActor.AnimationController.SkinnedBoneCustomRotations[k] =
                                    AnimationHelper.AnimateStatic(
                                    tree.TreeActor.AnimationController.SkinnedBoneCustomRotations[k].Value,
                                    Vector3.Zero, AnimationSpeed);
                            }
                        }
                    }
                }
            }
        }

        public override void Draw()
        {
            base.Draw();

            if (Engine.Editor)
            {                
                Representation.Draw();
                if (MaxDistance > 0 ||
                    LoseStrenghtDistance > 0)
                {
                    Engine.RenderManager.DrawBoundingSphere(Representation.Position, MaxDistance, 24, Color.Green,
                        Representation.Renderer.Camera);
                    Engine.RenderManager.DrawBoundingSphere(Representation.Position, LoseStrenghtDistance, 24, Color.Red,
                        Representation.Renderer.Camera);
                }
            }
        }

        public override void SerializeData()
        {
            base.SerializeData();
            Representation.SerializeData(Data);

            Data.AddData("Wind.Strenght", this.Strenght);
            Data.AddData("Wind.PerturbVariance", this.PerturbVariance);
            Data.AddData("Wind.PerturbTime", this.PerturbTime);
            Data.AddData("Wind.AnimationSpeed", this.AnimationSpeed);
            Data.AddData("Wind.Direction", this.Direction);
            Data.AddData("Wind.MaxDistance", this.MaxDistance);
            Data.AddData("Wind.LoseStrenghtDistance", this.LoseStrenghtDistance);
            Data.AddData("Representation.Position", this.Representation.Position);
        }
        public override void DeserializeData()
        {
            base.DeserializeData();
            Representation.DeserializeData(Data);

            this.Strenght = Data.GetData<float>("Wind.Strenght");
            this.PerturbVariance = Data.GetData<float>("Wind.PerturbVariance");
            this.PerturbTime = Data.GetData<float>("Wind.PerturbTime");
            this.MaxDistance = Data.GetData<float>("Wind.MaxDistance");
            this.LoseStrenghtDistance = Data.GetData<float>("Wind.LoseStrenghtDistance");
            this.AnimationSpeed = Data.GetData<int>("Wind.AnimationSpeed");
            this.Direction = Data.GetData<Vector3>("Wind.Direction");

            this.Representation.Position = Data.GetData<Vector3>("Representation.Position");
        }
    }
}
